﻿using gt.framework.Cache;
using gt.framework.Configuration;
using gt.framework.Utils;
using gt.rediscachemanager.Entry;
using System.Collections.Generic;
using System.Runtime.Caching;

namespace gt.rediscachemanager.Configuration
{
    public class RedisConfigManager
    {
        private static readonly string m_cacheConfigPath = "~/Configs/Redis_CacheManager.config";

        static RedisConfigManager()
        {
            var configValue = System.Configuration.ConfigurationManager.AppSettings["config:rediscachemanager"];
            if (!string.IsNullOrEmpty(configValue))
            {
                m_cacheConfigPath = configValue;
            }
        }

        public static string GetRedisCacheConfigFullPath()
        {
            return m_cacheConfigPath;
        }

        public static RedisCacheConfig GetRedisCacheConfigFromCache()
        {
            string fullPath = PathUtils.GetFullPath(m_cacheConfigPath);
            return GetConfigFromCacheWithPath<RedisCacheConfig>(new RedisCacheConfig().GetConfigKey(), fullPath);
        }

        public static T GetCachePoolFromCache<T>(string cacheKey)
            where T : ConfigBase, new()
        {
            RedisCacheConfig cacheConfig = GetRedisCacheConfigFromCache();
            if (cacheConfig == null || cacheConfig.ApplicationCaches == null) return default(T);
            var cachePoolConfig = cacheConfig.CachePathMappings.Find(e => string.Equals(e.Name, cacheKey));
            if (cachePoolConfig == null) return default(T);
            var fullPath = PathUtils.GetFullPath(cachePoolConfig.Path);
            return GetConfigFromCacheWithPath<T>(cacheKey, fullPath);
        }

        private static T GetConfigFromCacheWithPath<T>(string configKey, string fullPath)
            where T : ConfigBase, new()
        {
            if (string.IsNullOrEmpty(fullPath)) return default(T);
            T instance = CacheManager.Get<T>(configKey);
            if (instance == null)
            {
                lock (typeof(T))
                {
                    instance = CacheManager.Get<T>(configKey);
                    if (instance == null)
                    {
                        instance = InvokeGetConfig<T>(fullPath);
                        if (instance == null) return null;
                        List<string> configFiles = new List<string> { fullPath };

                        CacheManager.Insert<T>(configKey, instance, null, configFiles, new OnChangedCallback((o) =>
                        {
                            instance.ConfigChanged();
                        }));
                    }
                }
            }

            return instance ?? new T();
        }

        private static T InvokeGetConfig<T>(string fullPath) where T : class, new()
        {
            if (string.IsNullOrEmpty(fullPath)) return null;
            return (T)XmlFileUtils.LoadXml(fullPath, typeof(T));
        }

    }
}
